home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 2 / Gold Medal Software Volume 2 (Gold Medal) (1994).iso / prog / asm_n_z.arj / SETUP2.ASM < prev    next >
Assembly Source File  |  1989-03-06  |  42KB  |  1,355 lines

  1. ;=============================================================================
  2. ; SETUP 2.0 allows text and control codes to be sent directly to a printer
  3. ; from the command line or from within a popup menu window.  Syntax is:
  4. ;
  5. ;    SETUP2 [d:][path][filename] | [/C codes] | [/U]
  6. ;
  7. ; where filename = Name of PMF file
  8. ;    /C = Codes to be sent from the command line
  9. ;       /U = Uninstall the program
  10. ;=============================================================================
  11.  
  12. code        segment    para public 'code'
  13.         assume    cs:code
  14.         org    100h
  15. begin:        jmp    initialize
  16.  
  17. program        db    "SETUP 2.0 "
  18. copyright    db    "(c) 1989 Ziff Communications Co.",13,10
  19. author        db    "PC Magazine ",254," Jeff Prosise",13,10
  20. hotkey        db    "Hotkey is Ctrl-Rt/Shift",13,10,"$",1Ah
  21.  
  22. videocols    db    ?            ;number of columns displayed
  23. videopage    db    ?            ;active video page
  24. videoseg    dw    ?            ;video segment
  25. videostart    dw    ?            ;starting video address
  26. videocursormode    dw    ?            ;cursor description
  27. videocursorpos    dw    ?            ;BIOS cursor position
  28.  
  29. pname        db    26 dup (20h)        ;menu window title
  30. lpt_number    dw    0            ;LPT port number
  31. status        db    0            ;program status flag
  32. int9h        dd    ?            ;interrupt 9h vector
  33. window_start    label word
  34. window_x    db    ?            ;starting window column
  35. window_y    db    1            ;starting window row
  36. window_end    dw    ?            ;lower right window corner
  37. border_attr    db    ?            ;border color
  38. menu_attr    db    ?            ;window color
  39. hilite_attr    db    ?            ;highlight color
  40. cursor_def    dw    ?            ;default cursor definition
  41. index        db    0            ;menu selection index
  42. ten        db    10            ;base 10 divisor
  43. linecount    dw    0            ;number of menu lines
  44. pagecount    db    1            ;number of menu pages
  45. menupage    db    0            ;current menu page
  46. code_table    dw    offset menu_table    ;address of control code table
  47. end_offset    dw    offset menu_table    ;ending program address
  48.  
  49. ;=============================================================================
  50. ; KBINT receives control when an interrupt 9 is generated.
  51. ;=============================================================================
  52. kbint        proc    far
  53.         pushf                ;call BIOS keyboard routine
  54.         call    int9h
  55.         sti                ;enable interrupts
  56.         push    ax
  57.         mov    ah,2            ;get shift key status
  58.         int    16h
  59.         and    al,0Fh            ;mask off upper four bits
  60.         cmp    al,5            ;was the hotkey combo pressed?
  61.         pop    ax
  62.         jne    kb_exit            ;no, then exit
  63.         cmp    status,0        ;check program status
  64.         jne    kb_exit            ;exit if it's already up
  65.         call    main            ;pop up the window
  66. kb_exit:    iret                ;exit
  67. kbint        endp
  68.  
  69. ;=============================================================================
  70. ; MAIN is the main body of the program.
  71. ;=============================================================================
  72. main        proc    near
  73.         mov    status,1        ;set program status flag
  74.         push    ax            ;save all registers
  75.         push    bx
  76.         push    cx
  77.         push    dx
  78.         push    bp
  79.         push    si
  80.         push    di
  81.         push    ds
  82.         push    es
  83.         mov    ah,15            ;abort if the current video
  84.         int    10h            ;  mode is not a text mode
  85.         cmp    al,7
  86.         je    main1
  87.         cmp    al,4
  88.         jb    main1
  89. ;
  90. ;Restore register values and return to caller.
  91. ;
  92. main_exit:    pop    es            ;restore registers
  93.         pop    ds
  94.         pop    di
  95.         pop    si
  96.         pop    bp
  97.         pop    dx
  98.         pop    cx
  99.         pop    bx
  100.         pop    ax
  101.         mov    status,0        ;clear program status flag
  102.         ret
  103. ;
  104. ;Save video parameters and read the cursor address from the CRT controller.
  105. ;
  106. main1:        push    cs            ;establish DS addressability
  107.         pop    ds            ;  by pointing it to the
  108.         assume    ds:code            ;  code segment
  109.         cld                ;clear DF for string ops
  110.         mov    videocols,ah        ;save columns displayed
  111.         mov    videopage,bh        ;save active video page
  112.         mov    ah,3            ;get cursor information
  113.         int    10h
  114.         mov    videocursormode,cx    ;save cursor mode
  115.         mov    videocursorpos,dx    ;save cursor position
  116.         mov    ax,40h            ;point ES to the BIOS
  117.         mov    es,ax            ;  data area
  118.         mov    dx,es:[4Eh]        ;save video start address
  119.         mov    videostart,dx
  120. ;
  121. ;Define monochrome or color video attributes.
  122. ;
  123.         test    byte ptr es:[63h],40h    ;branch if this is
  124.         jnz    colorvideo        ;  a color system
  125.         mov    videoseg,0B000h        ;monochrome attributes
  126.         mov    border_attr,70h
  127.         mov    menu_attr,07h
  128.         mov    hilite_attr,70h
  129.         mov    cursor_def,0C0Dh
  130.         jmp    short vsave
  131. colorvideo:    mov    videoseg,0B800h        ;color attributes
  132.         mov    border_attr,70h
  133.         mov    menu_attr,4Fh
  134.         mov    hilite_attr,70h
  135.         mov    cursor_def,0607h
  136. ;
  137. ;Save video memory underlying the menu window, then open the window.
  138. ;
  139. vsave:        mov    ah,1            ;hide the cursor
  140.         mov    ch,20h
  141.         int    10h
  142.         mov    cl,videocols        ;determine window position
  143.         sub    cl,32
  144.         mov    window_x,cl        ;save starting column number
  145.         mov    ch,window_y
  146.         mov    dx,cx
  147.         add    dx,101Dh        ;save coordinates of lower
  148.         mov    window_end,dx        ;  right window corner
  149.         push    cs            ;point ES:DI to screen buffer
  150.         pop    es
  151.         mov    di,offset screen_buffer
  152.         mov    ax,offset udr_vio2mem    ;call SCANREGION routine to
  153.         mov    cx,window_start        ;  buffer the contents of
  154.         mov    dx,window_end        ;  video memory
  155.         call    scanregion
  156.         call    openwindow        ;open printer menu window
  157.         mov    al,hilite_attr        ;draw menu selection bar
  158.         call    drawmenubar
  159. ;
  160. ;Monitor the keyboard for keystrokes and act upon the ones received.
  161. ;
  162. keyloop:    mov    ah,0            ;get a keystroke
  163.         int    16h
  164.         or    al,al            ;branch on extended keycodes
  165.         jz    functionkey
  166. ;
  167. ;Output control codes if ENTER was pressed.
  168. ;
  169.         cmp    al,13            ;check for ENTER keycode
  170.         jne    escape
  171.         call    outputlpt        ;output indexed control codes
  172.         jmp    keyloop            ;return to input loop
  173. ;
  174. ;Close the window and exit if ESC was pressed.
  175. ;
  176. escape:        cmp    al,27            ;check for ESC keycode
  177.         jne    slash
  178.         jmp    close            ;jump to exit routines
  179. ;
  180. ;Jump down to the input line if the slash key was pressed.
  181. ;
  182. slash:        cmp    al,"/"            ;check for slash character
  183.         jne    keyloop            ;ignore anything else
  184.         mov    al,menu_attr        ;blank the menu bar
  185.         call    drawmenubar
  186.         call    scanline        ;read input and send to LPT
  187.         mov    al,hilite_attr        ;redraw the menu bar
  188.         call    drawmenubar
  189.         jmp    keyloop            ;loop back for more
  190. ;
  191. ;Send the corresponding control codes if a function key was pressed.
  192. ;
  193. functionkey:    cmp    ah,59            ;determine whether or not a
  194.         jb    keyloop            ;  function key was pressed
  195.         cmp    ah,68
  196.         ja    up_arrow
  197.         push    ax            ;save extended keycode
  198.         mov    al,menu_attr        ;erase the menu bar
  199.         call    drawmenubar
  200.         pop    ax            ;recover keycode
  201.         sub    ah,59            ;calculate new INDEX value
  202.         mov    index,ah
  203.         mov    al,hilite_attr        ;draw new menu bar
  204.         call    drawmenubar
  205.         call    outputlpt        ;output corresponding codes
  206.         jmp    keyloop            ;return to input loop
  207. ;
  208. ;Move the menu bar up one line if up-arrow was pressed.
  209. ;
  210. up_arrow:    cmp    ah,72            ;check for up-arrow
  211.         jne    dn_arrow
  212.         mov    al,menu_attr        ;erase the menu bar
  213.         call    drawmenubar
  214.         dec    index            ;decrement INDEX and wrap
  215.         jns    newbar            ;  if necessary
  216.         mov    index,9
  217. newbar:        mov    al,hilite_attr        ;redraw the menu bar
  218.         call    drawmenubar
  219.         jmp    keyloop            ;return to input loop
  220. ;
  221. ;Move the menu bar down one line if down-arrow was pressed.
  222. ;
  223. dn_arrow:    cmp    ah,80            ;check for down-arrow
  224.         jne    pgup
  225.         mov    al,menu_attr        ;erase the menu bar
  226.         call    drawmenubar
  227.         inc    index            ;increment INDEX and wrap
  228.         cmp    index,10        ;  around if necessary
  229.         jne    newbar            ;jump to finish up
  230.         mov    index,0
  231.         jmp    newbar
  232. ;
  233. ;Flip to the preceding menu page if PgUp was pressed.
  234. ;
  235. pgup:        cmp    ah,73            ;check for PgUp
  236.         jne    pgdn
  237.         cmp    pagecount,1        ;ignore if there is only
  238.         je    retkey            ;  one menu
  239.         dec    menupage        ;set MENUPAGE to previous
  240.         jns    newpage            ;  page and wrap around
  241.         mov    al,pagecount        ;  if necessary
  242.         dec    al
  243.         mov    menupage,al
  244. newpage:    call    writemenu        ;write text of page to memory
  245.         mov    al,hilite_attr        ;redraw the menu bar
  246.         call    drawmenubar
  247. retkey:        jmp    keyloop            ;return to input loop
  248. ;
  249. ;Flip to the next page if PgDn was pressed.
  250. ;
  251. pgdn:        cmp    ah,81            ;check for PgDn
  252.         jne    retkey
  253.         cmp    pagecount,1        ;ignore if there is only
  254.         je    retkey            ;  one menu
  255.         inc    menupage        ;adjust MENUPAGE
  256.         mov    al,pagecount
  257.         cmp    menupage,al
  258.         jne    newpage            ;jump to finish up
  259.         mov    menupage,0
  260.         jmp    newpage
  261. ;
  262. ;Close the menu window.
  263. ;
  264. close:        mov    si,offset screen_buffer    ;point SI to buffer
  265.         mov    ax,offset udr_mem2vio    ;call SCANREGION routine to
  266.         mov    cx,window_start        ;  restore the contents of
  267.         mov    dx,window_end        ;  video memory
  268.         call    scanregion
  269. ;
  270. ;Restore the cursor mode and position, then exit.
  271. ;
  272. restore:    mov    ah,2            ;restore position
  273.         mov    bh,videopage
  274.         mov    dx,videocursorpos
  275.         int    10h
  276.         mov    ah,1            ;restore mode
  277.         mov    cx,videocursormode
  278.         int    10h
  279.         jmp    main_exit        ;return from interrupt
  280. main        endp
  281.  
  282. ;-----------------------------------------------------------------------------
  283. ; SCANREGION scans the cursor over the indicated region and calls a
  284. ; user-defined routine at each stop.
  285. ;   Entry:  AX    - offset address of user-defined routine
  286. ;           CH,CL - upper left corner of region
  287. ;           DH,DL - lower right corner of region
  288. ;-----------------------------------------------------------------------------
  289. addr_udr    dw    ?            ;routine address
  290. columns        dw    0            ;number of columns in region
  291.  
  292. scanregion    proc    near
  293.         mov    addr_udr,ax        ;save address
  294.         push    cx            ;save starting cursor position
  295.         sub    dl,cl            ;calculate number of columns
  296.         inc    dl
  297.         mov    byte ptr columns,dl
  298.         sub    dh,ch            ;calculate number of rows
  299.         inc    dh
  300.         mov    cl,dh
  301.         xor    ch,ch
  302.         pop    dx            ;retrieve cursor position
  303.         mov    bh,videopage        ;page number in BH
  304. scanreg1:    push    cx            ;save row counter
  305.         push    dx            ;save cursor position
  306.         mov    cx,columns        ;load column counter
  307. scanreg2:    mov    ah,2            ;position cursor
  308.         int    10h
  309.         call    word ptr cs:[addr_udr]    ;call user-defined
  310.         inc    dl            ;  routine and
  311.         loop    scanreg2        ;  advance the cursor
  312.         pop    dx            ;advance cursor to next row
  313.         inc    dh            ;  and loop until all rows
  314.         pop    cx            ;  are done
  315.         loop    scanreg1
  316.         ret
  317. scanregion    endp
  318.  
  319. ;-----------------------------------------------------------------------------
  320. ; UDR_VIO2MEM is called by SCANREGION to save the contents of a screen area.
  321. ;   Entry:  ES:DI - buffer address
  322. ;-----------------------------------------------------------------------------
  323. udr_vio2mem    proc    near
  324.         mov    ah,8            ;get character and attribute
  325.         int    10h            ;  under the cursor
  326.         stosw                ;buffer them
  327.         ret
  328. udr_vio2mem    endp
  329.  
  330. ;-----------------------------------------------------------------------------
  331. ; UDR_MEM2VIO is called by SCANREGION to write to a screen area.
  332. ;   Entry:  DS:SI - buffer address
  333. ;-----------------------------------------------------------------------------
  334. udr_mem2vio    proc    near
  335.         push    cx            ;save CX
  336.         lodsw                ;get character and attribute
  337.         mov    bl,ah            ;attribute to BL
  338.         mov    ah,9            ;write character/attribute
  339.         mov    cx,1
  340.         int    10h
  341.         pop    cx            ;restore CX and exit
  342.         ret
  343. udr_mem2vio    endp
  344.  
  345. ;-----------------------------------------------------------------------------
  346. ; OPENWINDOW displays the printer control window.
  347. ;-----------------------------------------------------------------------------
  348. ftext        db    "1 2 3 4 5 6 7 8 9 10"
  349.  
  350. openwindow    proc    near
  351.         mov    ax,0600h        ;blank window region
  352.         mov    bh,menu_attr
  353.         mov    cx,window_start
  354.         mov    dx,window_end
  355.         int    10h
  356.         mov    cx,window_start        ;draw box around region to
  357.         mov    dx,window_end        ;  form window border
  358.         mov    bl,border_attr
  359.         call    textbox
  360.         mov    dx,window_start        ;display window title
  361.         add    dx,0102h
  362.         push    dx
  363.         mov    si,offset pname
  364.         mov    cx,26
  365.         call    writeln
  366.         pop    dx
  367.         inc    dh
  368.         push    dx            ;draw first horizontal
  369.         mov    cx,26            ;  divider
  370.         mov    bl,menu_attr
  371.         call    drawhorizontal
  372.         pop    dx
  373.         inc    dh
  374.         mov    cx,10            ;draw "F1".."F10" designators
  375.         mov    si,offset ftext
  376. open1:        push    cx
  377.         push    dx
  378.         mov    ah,2
  379.         int    10h
  380.         mov    ax,0E46h
  381.         int    10h
  382.         inc    dl
  383.         mov    cx,2
  384.         call    writeln
  385.         pop    dx
  386.         inc    dh
  387.         pop    cx
  388.         loop    open1
  389.         push    dx            ;draw second horizontal
  390.         mov    cx,26            ;  divider
  391.         mov    bl,menu_attr
  392.         call    drawhorizontal
  393.         pop    dx
  394.         inc    dh
  395.         push    dx            ;draw input line
  396.         mov    al,hilite_attr
  397.         mov    cx,26
  398.         call    writeattr
  399.         pop    dx
  400.         inc    dh
  401.         mov    si,offset menutxt    ;display menu line
  402.         mov    cx,24
  403.         call    writeln
  404.         call    writemenu        ;display current menu
  405.         ret
  406. openwindow    endp
  407.  
  408. ;-----------------------------------------------------------------------------
  409. ; WRITELN displays a text string of known length.
  410. ;   Entry:  DS:SI - string address
  411. ;           DH,DL - starting row and column
  412. ;           CX    - string length
  413. ;-----------------------------------------------------------------------------
  414. writeln        proc    near
  415.         mov    ah,2            ;position cursor
  416.         mov    bh,videopage
  417.         int    10h
  418. wln1:        lodsb                ;get a byte
  419.         mov    ah,0Eh            ;display it and advance the
  420.         int    10h            ;  cursor one column
  421.         loop    wln1            ;loop until done
  422.         ret
  423. writeln        endp
  424.  
  425. ;-----------------------------------------------------------------------------
  426. ; TEXTBOX draws a box of specified color around a region.
  427. ;   Entry:  CH,CL - upper left corner row and column
  428. ;           DH,DL - lower right corner row and column
  429. ;           BL    - attribute
  430. ;-----------------------------------------------------------------------------
  431. wide        dw    0            ;region width
  432. height        dw    0            ;region height
  433. upleft        dw    ?            ;upper left row and column
  434.  
  435. textbox        proc    near
  436.         mov    upleft,cx        ;save coordinates
  437.         sub    dh,ch            ;calculate height
  438.         dec    dh
  439.         mov    byte ptr height,dh
  440.         sub    dl,cl            ;calculate width
  441.         dec    dl
  442.         mov    byte ptr wide,dl
  443.         mov    bh,videopage        ;set BH for video calls
  444.         mov    ah,2            ;draw upper left corner
  445.         mov    dx,upleft
  446.         int    10h
  447.         mov    ax,09DAh
  448.         mov    cx,1
  449.         int    10h
  450.         inc    dl            ;draw top horizontal line
  451.         mov    cx,wide
  452.         call    drawhorizontal
  453.         mov    ah,2            ;draw upper right corner
  454.         add    dl,byte ptr wide
  455.         int    10h
  456.         mov    ax,09BFh
  457.         mov    cx,1
  458.         int    10h
  459.         mov    ah,2            ;draw lower left corner
  460.         mov    dx,upleft
  461.         add    dh,byte ptr height
  462.         inc    dh
  463.         int    10h
  464.         mov    ax,09C0h
  465.         mov    cx,1
  466.         int    10h
  467.         inc    dl            ;draw bottom horizontal line
  468.         mov    cx,wide
  469.         call    drawhorizontal
  470.         mov    ah,2            ;draw lower right corner
  471.         add    dl,byte ptr wide
  472.         int    10h
  473.         mov    ax,09D9h
  474.         mov    cx,1
  475.         int    10h
  476.         mov    dx,upleft        ;draw left vertical
  477.         inc    dh
  478.         push    dx
  479.         mov    cx,height
  480.         call    drawvertical
  481.         pop    dx
  482.         add    dl,byte ptr wide    ;draw right vertical
  483.         inc    dl
  484.         mov    cx,height
  485.         call    drawvertical
  486.         ret
  487. textbox        endp
  488.  
  489. ;-----------------------------------------------------------------------------
  490. ; DRAWHORIZONTAL draws a horizontal line of specified length.
  491. ;   Entry:  DH,DL - starting row and column
  492. ;           CX    - length
  493. ;           BL    - attribute
  494. ;-----------------------------------------------------------------------------
  495. drawhorizontal    proc    near
  496.         mov    ah,2            ;set cursor position
  497.         mov    bh,videopage
  498.         int    10h
  499.         mov    ax,09C4h        ;draw line
  500.         int    10h
  501.         ret
  502. drawhorizontal    endp
  503.  
  504. ;-----------------------------------------------------------------------------
  505. ; DRAWVERTICAL draws a vertical line of specified length.
  506. ;   Entry:  DH,DL - starting row and column
  507. ;           CX    - length
  508. ;           BL    - attribute
  509. ;-----------------------------------------------------------------------------
  510. drawvertical    proc    near
  511.         mov    bh,videopage
  512. vdraw1:        push    cx
  513.         mov    ah,2            ;position cursor
  514.         int    10h
  515.         mov    ax,09B3h        ;draw one character
  516.         mov    cx,1
  517.         int    10h
  518.         inc    dh            ;move cursor to next line
  519.         pop    cx
  520.         loop    vdraw1            ;loop until done
  521.         ret
  522. drawvertical    endp
  523.  
  524. ;-----------------------------------------------------------------------------
  525. ; WRITEMENU displays a page of menu text.
  526. ;   Entry:  MENUPAGE - menu page number
  527. ;-----------------------------------------------------------------------------
  528. writemenu    proc    near
  529.         mov    al,menupage        ;point SI to menu text
  530.         mov    bl,200
  531.         mul    bl
  532.         mov    si,ax
  533.         add    si,offset menu_table
  534.         mov    ax,0600h        ;blank current menu
  535.         mov    bh,menu_attr
  536.         mov    cx,window_start
  537.         add    cx,0308h
  538.         push    cx
  539.         mov    dx,cx
  540.         add    dx,0913h
  541.         int    10h
  542.         pop    dx
  543.         mov    cx,10            ;determine how many lines are
  544.         mov    al,pagecount        ;  to be written
  545.         dec    al
  546.         cmp    al,menupage
  547.         jne    wmloop
  548.         mul    ten
  549.         mov    cx,linecount
  550.         sub    cx,ax
  551.         jcxz    nomenu
  552. wmloop:        push    cx            ;save line counter
  553.         push    dx            ;save cursor position
  554.         mov    cx,20            ;display one line of menu text
  555.         call    writeln
  556.         pop    dx            ;advance cursor to next line
  557.         inc    dh
  558.         pop    cx
  559.         loop    wmloop            ;loop until done
  560. nomenu:        ret
  561. writemenu    endp
  562.  
  563. ;-----------------------------------------------------------------------------
  564. ; WRITEATTR writes a series of attribute bytes to video memory.  Writing is
  565. ; performed during the vertical retrace on color adapters.
  566. ;   Entry:  AL    - attribute
  567. ;           CX    - number of attributes to write
  568. ;        DH,DL - starting row and column
  569. ;-----------------------------------------------------------------------------
  570. writeattr    proc    near
  571.         push    ax            ;save attribute
  572.         mov    al,videocols        ;calculate address of the
  573.         mul    dh            ;  indicated character cell
  574.         xor    dh,dh            ;  in video memory
  575.         add    ax,dx
  576.         shl    ax,1
  577.         add    ax,videostart
  578.         mov    di,ax
  579.         inc    di
  580.         mov    es,videoseg        ;point ES to video memory
  581.         cmp    videoseg,0B000h        ;don't wait if display
  582.         je    nowait            ;  is monochrome
  583.         mov    dx,3DAh            ;address CRTC status register
  584. wait_for_vert:    in    al,dx            ;wait for vertical retrace
  585.         test    al,8
  586.         jz    wait_for_vert
  587. nowait:        pop    ax            ;retrieve attribute
  588. attrloop:    stosb                ;write attributes
  589.         inc    di
  590.         loop    attrloop
  591.         ret
  592. writeattr    endp
  593.  
  594. ;-----------------------------------------------------------------------------
  595. ; DRAWMENUBAR draws or erases the menu selection bar.
  596. ;   Entry:  AL    - attribute
  597. ;           INDEX - selection index number
  598. ;-----------------------------------------------------------------------------
  599. drawmenubar    proc    near
  600.         mov    dx,window_start        ;calculate starting row and
  601.         add    dh,index        ;  column
  602.         add    dx,0302h
  603.         mov    cx,26            ;26 character cells to alter
  604.         call    writeattr        ;write the attribute bytes
  605.         ret
  606. drawmenubar    endp
  607.  
  608. ;-----------------------------------------------------------------------------
  609. ; SCANLINE reads an input string from the keyboard, converts ASCII numbers
  610. ; to binary, and sends them to the designated printer port.
  611. ;-----------------------------------------------------------------------------
  612. input_pos    dw    ?            ;row and column of input line
  613.  
  614. scanline    proc    near
  615.         push    cs            ;point ES:DI to input buffer
  616.         pop    es
  617.         mov    di,offset input_buffer
  618.         mov    dx,window_start        ;position the cursor
  619.         add    dx,0E02h
  620.         mov    input_pos,dx        ;save coordinates
  621.         mov    ah,2
  622.         mov    bh,videopage
  623.         int    10h
  624.         mov    ah,1            ;unblank the cursor
  625.         mov    cx,cursor_def
  626.         int    10h
  627.         xor    cl,cl            ;zero character count
  628. ;
  629. ;Read and buffer keystrokes until ENTER or ESC is pressed.
  630. ;
  631. scanloop:    mov    ah,0            ;wait for a keystroke
  632.         int    16h
  633.         cmp    al,8            ;check for backspace
  634.         jne    scan1
  635.         or    cl,cl            ;ignore backspace if count
  636.         jz    scanloop        ;  is zero
  637.         call    backspace        ;perform backspace
  638.         jmp    scanloop        ;return to input loop
  639. scan1:        cmp    al,13            ;branch if ENTER pressed
  640.         je    endscan
  641.         cmp    al,27            ;branch if ESC pressed
  642.         je    esckey
  643.         cmp    al,32            ;ignore control codes
  644.         jb    scanloop
  645.         cmp    cl,255            ;ignore the character if
  646.         je    scanloop        ;  input buffer is full
  647.         call    insert_char        ;buffer the character
  648.         jmp    scanloop        ;return to input loop
  649. ;
  650. ;Parse the text just entered and output binary codes to the printer.
  651. ;
  652. endscan:    mov    es:[di],al        ;buffer EOL character
  653.         push    bx            ;save registers
  654.         push    cx
  655.         push    di
  656.         mov    si,offset input_buffer    ;point SI to text
  657.         mov    di,offset output_buffer    ;point DI to output buffer
  658.         call    asc2bin            ;convert ASCII to binary
  659.         jnc    checkstat        ;continue if no error
  660.         mov    si,offset errtxt1    ;display error message if
  661. scan2:        call    win_error        ;  code string is invalid
  662.         pop    di            ;restore registers
  663.         pop    cx
  664.         pop    bx
  665.         jmp    scanloop        ;return to input loop
  666. checkstat:    call    lptstatus        ;check printer status
  667.         jnc    scan3            ;continue if printer ready
  668.         mov    si,offset errtxt2    ;display error message
  669.         jmp    scan2
  670. scan3:        mov    si,offset output_buffer    ;point SI to codes
  671.         call    sendlptcodes        ;output them
  672.         add    sp,6            ;clean up the stack
  673. ;
  674. ;Clear the input line and exit.
  675. ;
  676. esckey:        mov    ah,1            ;blank the cursor
  677.         mov    ch,20h
  678.         int    10h
  679.         mov    ah,2            ;position cursor on input line
  680.         mov    dx,input_pos
  681.         mov    bh,videopage
  682.         int    10h
  683.         mov    ax,0A20h        ;blank the input line
  684.         mov    cx,25
  685.         int    10h
  686.         ret                ;and exit
  687. scanline    endp
  688.  
  689. ;-----------------------------------------------------------------------------
  690. ; BACKSPACE deletes the character left of the cursor.
  691. ;-----------------------------------------------------------------------------
  692. backspace    proc    near
  693.         dec    cl            ;decrement character count
  694.         dec    di            ;decrement buffer pointer
  695.         cmp    cl,24            ;branch if count > 24
  696.         ja    refresh
  697.         push    cx            ;save character count
  698.         mov    ah,0Eh            ;move the cursor back one
  699.         int    10h            ;  space
  700.         mov    ax,0A20h        ;overwrite character under the
  701.         mov    cx,1            ;  cursor with a space
  702.         int    10h
  703.         pop    cx            ;restore count
  704.         ret
  705. refresh:    push    cx            ;save character count
  706.         mov    si,di            ;scroll the input line one
  707.         sub    si,25            ;  character to the right to
  708.         mov    cx,25            ;  blank the last character
  709.         mov    dx,input_pos
  710.         call    writeln
  711.         pop    cx            ;restore count
  712.         ret
  713. backspace    endp
  714.  
  715. ;-----------------------------------------------------------------------------
  716. ; INSERT_CHAR inserts a character into the input buffer.
  717. ;-----------------------------------------------------------------------------
  718. insert_char    proc    near
  719.         stosb                ;buffer the character
  720.         inc    cl            ;increment character count
  721.         cmp    cl,25            ;branch if count > 25
  722.         ja    refresh
  723.         mov    ah,0Eh            ;display the character
  724.         int    10h
  725.         ret
  726. insert_char    endp
  727.  
  728. ;-----------------------------------------------------------------------------
  729. ; ASC2BIN converts an ASCII text string into a string of binary bytes.
  730. ;   Entry:  DS:SI - text string address
  731. ;        ES:DI - binary buffer address
  732. ;   Exit:   CF clear = no error, CF set = error
  733. ;        CL - number of codes converted
  734. ;-----------------------------------------------------------------------------
  735. asc2bin        proc    near
  736.         push    di            ;save count byte address
  737.         inc    di            ;advance past count byte
  738.         xor    cl,cl            ;zero count
  739.         xor    bh,bh            ;zero BH
  740. a2bloop:    mov    dx,0A00h        ;initialize DH (base) and
  741.                         ;  DL (accumulator)
  742. ;
  743. ;Search until the first character of an entry or EOL marker is encountered.
  744. ;
  745. nextchar:    lodsb                ;get a character
  746.         call    check_20_2c        ;skip spaces, commas, and tabs
  747.         jz    nextchar
  748.         cmp    al,0Dh            ;done if EOL encountered
  749.         je    endconvert
  750.         cmp    al,"/"            ;done if slash encountered
  751.         je    endconvert
  752.         call    check_22_27        ;check for " or ' mark
  753.         jnz    isdigit            ;branch if neither
  754. ;
  755. ;Buffer everything between quotation marks or apostrophes.
  756. ;
  757. inquotes:    lodsb                ;get next character
  758.         call    check_22_27        ;exit loop if ending quote
  759.         jz    nextchar        ;  symbol is encountered
  760.         cmp    al,0Dh            ;exit if line terminator is
  761.         je    endconvert        ;  is encountered
  762.         stosb                ;buffer the character
  763.         inc    cl            ;increment count
  764.         jz    a2berror        ;error if count > 255
  765.         jmp    inquotes        ;loop back for more
  766. ;
  767. ;Convert a numeric entry to binary.
  768. ;
  769. digitloop:    lodsb                ;get next character
  770.         call    check_20_2c        ;check for delimiter marking
  771.         jz    endnumtext        ;  end of the current number
  772.         call    check_22_27
  773.         jz    endnumtext
  774.         cmp    al,0Dh            ;check for end-of-line
  775.         je    endnumtext
  776. isdigit:    cmp    al,30h            ;digit is valid if it lies
  777.         jb    a2berror        ;  between "0" and "9"
  778.         cmp    al,3Ah
  779.         jb    ascii_adjust
  780.         and    al,0DFh            ;capitalize presumed alpha
  781.         cmp    al,"X"            ;change base to 16 for hex
  782.         jne    check_hex        ;  numbers if "X" is found
  783.         mov    dh,16
  784.         jmp    digitloop
  785. check_hex:    cmp    dh,16            ;error if this isn't base 16
  786.         jne    a2berror
  787.         cmp    al,41h            ;digit is valid if it lies
  788.         jb    a2berror        ;  between "A" and "F"
  789.         cmp    al,46h
  790.         ja    a2berror
  791.         sub    al,7            ;hex conversion
  792. ascii_adjust:    sub    al,30h            ;ASCII to binary conversion
  793.         mov    bl,al            ;save digit
  794.         mov    al,dl            ;multiply accumulator by base
  795.         mul    dh
  796.         add    ax,bx            ;add new digit to result
  797.         or    ah,ah            ;error if result > 255
  798.         jnz    a2berror
  799.         mov    dl,al            ;put new value in accumulator
  800.         jmp    digitloop        ;get next digit
  801. a2berror:    pop    bx            ;clean up the stack
  802.         xor    cl,cl            ;zero CX on error
  803.         mov    es:[bx],cl        ;store zero in buffer
  804.         stc                ;set CF for error
  805.         ret
  806. endnumtext:    mov    al,dl            ;write accumulator value to
  807.         stosb                ;  binary buffer
  808.         inc    cl            ;increment count
  809.         jz    a2berror        ;error if count > 255
  810.         dec    si            ;point SI to terminator
  811.         jmp    a2bloop            ;search for next number
  812. ;
  813. ;Do housekeeping and exit.
  814. ;
  815. endconvert:    pop    bx            ;recover count byte address
  816.         mov    es:[bx],cl        ;store count in buffer
  817.         clc                ;clear CF for exit
  818.         ret
  819. asc2bin        endp
  820.  
  821. ;-----------------------------------------------------------------------------
  822. ; CHECK_20_2C returns a flag if AL holds an ASCII space, comma, or tab.
  823. ;   Entry:  AL - character
  824. ;   Exit:   ZF clear = no match, ZF set = space or comma
  825. ;-----------------------------------------------------------------------------
  826. check_20_2c    proc    near
  827.         cmp    al,20h            ;check for ASCII space
  828.         je    ischar1
  829.         cmp    al,2Ch            ;check for ASCII comma
  830.         je    ischar1
  831.         cmp    al,9            ;check for ASCII tab
  832. ischar1:    ret
  833. check_20_2c    endp
  834.  
  835. ;-----------------------------------------------------------------------------
  836. ; CHECK_22_27 returns a flag if AL holds an ASCII quote mark or apostrophe.
  837. ;   Entry:  AL - character
  838. ;   Exit:   ZF clear = no match, ZF set = space or comma
  839. ;-----------------------------------------------------------------------------
  840. check_22_27    proc    near
  841.         cmp    al,22h            ;check for quotation mark
  842.         je    ischar2
  843.         cmp    al,27h            ;check for apostrophe
  844. ischar2:    ret
  845. check_22_27    endp
  846.  
  847. ;-----------------------------------------------------------------------------
  848. ; LPTSTATUS checks the status of the indicated printer.
  849. ;   Entry:  LPT_NUMBER - printer number (0-2)
  850. ;   Exit:   CF clear = printer ready, CF set = printer not ready
  851. ;-----------------------------------------------------------------------------
  852. lptstatus    proc    near
  853.         mov    ah,2            ;get status byte from BIOS
  854.         mov    dx,lpt_number
  855.         int    17h
  856.         test    ah,29h            ;check bits 0, 3, and 5
  857.         jnz    notready        ;error if one is set
  858.         test    ah,0F9h            ;check all but bits 1 and 2
  859.         jz    notready        ;error if all are zero
  860.         clc                ;clear CF for return
  861.         ret
  862. notready:    stc                ;set CF for return
  863.         ret
  864. lptstatus    endp
  865.  
  866. ;-----------------------------------------------------------------------------
  867. ; SENDLPTCODES sends a string of bytes to the designated printer.
  868. ;   Entry:  DS:SI      - string (first byte = length)
  869. ;        LPT_NUMBER - printer number (0-2)
  870. ;-----------------------------------------------------------------------------
  871. sendlptcodes    proc    near
  872.         lodsb                ;get string length in CX
  873.         mov    cl,al
  874.         xor    ch,ch
  875.         jcxz    nosend            ;exit if length is zero
  876.         mov    dx,lpt_number        ;initialize DX
  877. sendloop:    lodsb                ;loop until all bytes are
  878.         mov    ah,0            ;  output
  879.         int    17h
  880.         loop    sendloop
  881. nosend:        ret
  882. sendlptcodes    endp
  883.  
  884. ;-----------------------------------------------------------------------------
  885. ; OUTPUTLPT sends the string of control codes indexed by INDEX and MENUPAGE
  886. ; to the printer designated by LPT_NUMBER.
  887. ;-----------------------------------------------------------------------------
  888. outputlpt    proc    near
  889.         call    lptstatus        ;check printer status
  890.         jnc    isready
  891.         mov    si,offset errtxt2    ;error if printer is not
  892.         call    win_error        ;  ready
  893. no_output:    ret
  894. isready:    mov    al,menupage        ;calculate offset address
  895.         mul    ten            ;  of control code string
  896.         add    al,index        ;  from MENUPAGE and INDEX
  897.         cmp    ax,linecount        ;make sure a control code
  898.         jae    no_output        ;  string is defined
  899.         mov    cx,ax
  900.         mov    si,code_table        ;find offset address of the
  901.         jcxz    nocalc            ;  corresponding code string
  902. outloop:    mov    al,[si]            ;  by scanning the linked
  903.         inc    al            ;  list of control codes
  904.         add    si,ax
  905.         loop    outloop
  906. nocalc:        call    sendlptcodes        ;output the code string
  907.         ret
  908. outputlpt    endp
  909.  
  910. ;-----------------------------------------------------------------------------
  911. ; WIN_ERROR displays an error message and waits for a keystroke.
  912. ;   Entry:  DS:SI - text address
  913. ;-----------------------------------------------------------------------------
  914. menutxt        db    "Esc Enter /",20h,18h,19h,20h,"PgUp PgDn"
  915. errtxt1        db    "Error: Invalid entry",4 dup (20h)
  916. errtxt2        db    "Error: Printer not ready"
  917.  
  918. win_error    proc    near
  919.         call    disp_err_msg        ;display error message
  920.         mov    ax,0E07h        ;beep
  921.         int    10h
  922. win1:        mov    ah,1            ;loop until a key is
  923.         int    16h            ;  pressed
  924.         jz    win1
  925.         mov    si,offset menutxt    ;restore original text
  926.         call    disp_err_msg
  927.         ret
  928. win_error    endp
  929.  
  930. ;-----------------------------------------------------------------------------
  931. ; DISP_ERR_MSG displays a window error message.
  932. ;   Entry:  DS:SI - text address
  933. ;-----------------------------------------------------------------------------
  934. disp_err_msg    proc    near
  935.         mov    ah,3            ;get cursor position
  936.         mov    bh,videopage
  937.         int    10h
  938.         push    dx            ;save it
  939.         mov    dx,window_start        ;display error message
  940.         add    dx,0F02h
  941.         mov    cx,24
  942.         call    writeln
  943.         mov    ah,2            ;restore cursor position
  944.         pop    dx
  945.         int    10h
  946.         ret
  947. disp_err_msg    endp
  948.  
  949. ;=============================================================================
  950. ; INITIALIZE handles command line directives and installation/deinstallation.
  951. ;=============================================================================
  952. errmsg1        db    "Usage: SETUP2 [d:][path][filename] | [/C codes] | [/U]$"
  953. errmsg2        db    "Already installed$"
  954. errmsg3        db    "Cannot uninstall$"
  955. errmsg4        db    "Not installed$"
  956. errmsg6        db    "Invalid code string$"
  957. errmsg7        db    "Printer not ready$"
  958. errmsg8        db    "File not found$"
  959. errmsg9        db    "File too large$"
  960. errmsg10    db    "Insufficient memory$"
  961. errmsg11    db    "Make file error - line $"
  962. initmsg1    db    "Uninstalled$"
  963. installed    db    0
  964.  
  965. initialize    proc    near
  966.         assume    cs:code, ds:code
  967. ;
  968. ;See if a copy is already resident in memory.
  969. ;
  970.         cld                ;clear DF
  971.         mov    word ptr [begin],0    ;initialize fingerprint
  972.         xor    bx,bx            ;zero BX for start
  973.         mov    ax,cs            ;keep CS value in AX
  974. init1:        inc    bx            ;increment search segment value
  975.         mov    es,bx
  976.         cmp    ax,bx            ;not installed if current
  977.         je    parse            ;  segment is looped back to
  978.         mov    si,offset begin        ;search this segment for ASCII
  979.         mov    di,si            ;  fingerprint
  980.         mov    cx,16
  981.         repe    cmpsb
  982.         jne    init1            ;loop back if not found
  983.         mov    installed,1        ;set installed flag
  984. ;
  985. ;Parse the command line for entries and take appropriate action.
  986. ;
  987. parse:        mov    si,81h            ;point SI to command line
  988. parseloop:    lodsb                ;get a character
  989.         cmp    al,20h            ;skip it if it's a space
  990.         je    parseloop
  991.         cmp    al,0Dh            ;exit loop when a carriage
  992.         jne    init2            ;  return is encountered
  993.         jmp    install
  994. init2:        cmp    al,"/"            ;check for "/" modifier
  995.         je    init3            ;branch if found
  996.         mov    dx,offset errmsg2    ;initialize error pointer
  997.         cmp    installed,0        ;check installed flag
  998.         jne    error_exit        ;error if already installed
  999.         dec    si            ;point SI to filename
  1000.         call    make            ;process printer make file
  1001.         jmp    setvec            ;install
  1002. init3:        lodsb                ;get parameter
  1003.         and    al,0DFh            ;capitalize
  1004.         cmp    al,"U"            ;branch to handling routine
  1005.         je    uninstall
  1006.         cmp    al,"C"
  1007.         je    readcodes
  1008. ;
  1009. ;An error was encountered in parsing.  Display error message and exit.
  1010. ;
  1011. syntax_error:    mov    dx,offset errmsg1    ;display error message
  1012. error_exit:    mov    ah,9
  1013.         int    21h
  1014.         mov    ax,4C01h        ;exit with ERRORLEVEL = 1
  1015.         int    21h
  1016. ;
  1017. ;Process a /U command line parameter.
  1018. ;
  1019. uninstall:    mov    dx,offset errmsg4    ;error if not installed
  1020.         cmp    installed,1
  1021.         jne    error_exit
  1022.         call    remove            ;call uninstall routine
  1023.         mov    dx,offset errmsg3    ;exit on error
  1024.         jc    error_exit
  1025.         mov    dx,offset initmsg1    ;display "Uninstalled"
  1026.         mov    ah,9            ;  message
  1027.         int    21h
  1028.         mov    ax,4C00h        ;exit with ERRORLEVEL = 0
  1029.         int    21h
  1030. ;
  1031. ;Process a /C command line parameter.
  1032. ;
  1033. readcodes:    push    cs            ;set ES to code segment
  1034.         pop    es
  1035.         mov    di,offset menu_table    ;point DI to scratch area
  1036.         call    asc2bin            ;convert text to binary
  1037.         mov    dx,offset errmsg6    ;exit on conversion error
  1038.         jc    error_exit
  1039.         or    cl,cl            ;exit if no codes were entered
  1040.         jz    error_exit
  1041.         call    lptstatus        ;check printer status
  1042.         mov    dx,offset errmsg7
  1043.         jc    error_exit        ;error if printer not ready
  1044.         mov    si,offset menu_table    ;point SI to output buffer
  1045.         call    sendlptcodes        ;output control codes
  1046. read_exit:    mov    ax,4C00h        ;exit with ERRORLEVEL = 0
  1047.         int    21h
  1048. ;
  1049. ;Make sure a copy isn't already loaded before installing this one.
  1050. ;
  1051. install:    mov    dx,offset errmsg2    ;initialize error pointer
  1052.         cmp    installed,0        ;check installed flag
  1053.         jne    error_exit        ;error if already installed
  1054. ;
  1055. ;Reset the interrupt 9h vector to an internal handler.
  1056. ;
  1057. setvec:        mov    ax,3509h        ;save old vector
  1058.         int    21h
  1059.         mov    word ptr int9h,bx
  1060.         mov    word ptr int9h[2],es
  1061.         mov    ax,2509h        ;then set the new vector
  1062.         mov    dx,offset kbint
  1063.         int    21h
  1064. ;
  1065. ;Deallocate the program's environment block.
  1066. ;
  1067.         mov    ax,ds:[2Ch]        ;get environment segment
  1068.         mov    es,ax
  1069.         mov    ah,49h            ;free it
  1070.         int    21h
  1071. ;
  1072. ;Display copyright notice, then terminate and remain resident in memory.
  1073. ;
  1074.         mov    ah,9            ;display message
  1075.         mov    dx,offset program
  1076.         int    21h
  1077.         mov    ax,3100h        ;terminate with ERRORLEVEL = 0
  1078.         mov    dx,end_offset        ;calculate amount of memory
  1079.         sub    dx,offset code - 15    ;  to reserve in DX
  1080.         mov    cl,4            ;convert bytes to paragraphs
  1081.         shr    dx,cl
  1082.         int    21h            ;terminate
  1083. initialize    endp
  1084.  
  1085. ;-----------------------------------------------------------------------------
  1086. ; REMOVE deallocates the memory block addressed by ES and restores the
  1087. ; interrupt vector displaced on installation.
  1088. ;   Entry:  ES - segment to release
  1089. ;   Exit:   CF clear - program uninstalled
  1090. ;        CF set   - can't uninstall
  1091. ;-----------------------------------------------------------------------------
  1092. remove          proc    near
  1093.         mov    cx,es            ;abort if the interrupt 9
  1094.         mov    ax,3509h        ;  vector has been altered
  1095.         int    21h            ;  since installation
  1096.         mov    ax,es
  1097.         cmp    ax,cx
  1098.         jne    remove_error
  1099.         mov    es,cx
  1100.                 mov     ah,49h                  ;free memory given to
  1101.                 int     21h                     ;  original program block
  1102.         jc    remove_error        ;branch on error
  1103.         push    ds            ;restore interrupt vector
  1104.                 assume  ds:nothing
  1105.         mov    ax,2509h
  1106.         lds    dx,es:[int9h]
  1107.         int    21h
  1108.                 pop     ds
  1109.                 assume  ds:code
  1110.                 not     word ptr es:[begin]     ;destroy ASCII fingerprint
  1111.         clc                ;clear CF for exit
  1112.         ret
  1113. remove_error:    stc                ;set CF to indicate program
  1114.         ret                ;  couldn't be uninstalled
  1115. remove          endp
  1116.  
  1117. ;=============================================================================
  1118. ; MAKE reads a make file and builds the program's menu and code tables.
  1119. ;=============================================================================
  1120. handle        dw    ?            ;file handle
  1121. filesize    dw    ?            ;file size in bytes
  1122. fileseg        dw    ?            ;file buffer segment
  1123.  
  1124. make        proc    near
  1125.         mov    dx,si            ;save address of first char
  1126. make1:        lodsb                ;find end of filename
  1127.         cmp    al,0Dh
  1128.         je    make2
  1129.         cmp    al,20h
  1130.         jne    make1
  1131. make2:        mov    byte ptr [si-1],0    ;convert filename to ASCIIZ
  1132. ;
  1133. ;Open the printer make file and read it into memory.
  1134. ;
  1135.         mov    ax,3D00h        ;open the make file
  1136.         int    21h
  1137.         mov    dx,offset errmsg8    ;error if call failed
  1138.         jc    make_error2
  1139.         mov    handle,ax        ;save file handle
  1140.         mov    bx,ax            ;determine the file's size
  1141.         mov    ax,4202h        ;  in bytes
  1142.         xor    cx,cx
  1143.         xor    dx,dx
  1144.         int    21h
  1145.         or    dx,dx            ;error if greater than 64K
  1146.         jz    make3
  1147. make_error1:    mov    dx,offset errmsg9
  1148. make_error2:    jmp    error_exit
  1149. make3:        cmp    ax,0FFD0H
  1150.         ja    make_error1
  1151.         mov    filesize,ax        ;save file size
  1152.         mov    ah,4Ah            ;shrink memory allocation
  1153.         mov    bx,1000h        ;  to 64K
  1154.         push    cs
  1155.         pop    es
  1156.         int    21h
  1157.         mov    dx,offset errmsg10    ;insufficient memory if
  1158.         jc    make_error2        ;  call failed
  1159.         mov    ah,48h            ;request enough additional
  1160.         mov    bx,filesize        ;  memory to read in the
  1161.         add    bx,18            ;  make file
  1162.         mov    cl,4
  1163.         shr    bx,cl
  1164.         int    21h
  1165.         mov    dx,offset errmsg10    ;insufficient memory if
  1166.         jc    make_error2        ;  call failed
  1167.         mov    fileseg,ax        ;save segment address
  1168.         mov    ax,4200h        ;reset file pointer
  1169.         mov    bx,handle
  1170.         xor    cx,cx
  1171.         xor    dx,dx
  1172.         int    21h
  1173.         mov    ah,3Fh            ;read make file into the
  1174.         mov    bx,handle        ;  portion of memory just
  1175.         mov    cx,filesize        ;  allocated
  1176.         xor    dx,dx
  1177.         assume    ds:nothing
  1178.         mov    ds,fileseg
  1179.         int    21h
  1180.         mov    ah,3Eh            ;close the file
  1181.         mov    bx,handle
  1182.         int    21h
  1183.         mov    bx,filesize        ;find the end of the file
  1184.         cmp    byte ptr [bx-1],1Ah    ;delete last character if it
  1185.         jne    make4            ;  is a Ctrl-Z
  1186.         dec    bx
  1187. make4:        cmp    word ptr [bx-2],0A0Dh    ;add a carriage return/
  1188.         je    make5            ;  line feed pair if the
  1189.         mov    word ptr [bx],0A0Dh    ;  file doesn't already
  1190.         add    bx,2            ;  end with one
  1191. make5:        mov    byte ptr [bx],0        ;write terminating zero
  1192. ;
  1193. ;Copy the printer name from the printer make file.
  1194. ;
  1195.         push    cs            ;initialize DS:SI to address
  1196.         pop    es            ;  file buffer and ES:DI to
  1197.         xor    si,si            ;  address printer name
  1198.         mov    di,offset pname        ;  string
  1199. pname1:        call    skip_comment        ;skip comment lines
  1200. pname2:        cmp    byte ptr [si],0        ;exit if EOF is reached
  1201.         jne    pname3
  1202.         jmp    make_exit
  1203. pname3:        mov    cx,26
  1204. pname4:        lodsb                ;get a character
  1205.         cmp    al,0Dh            ;quit now if the character is
  1206.         jne    pname5            ;  a carriage return
  1207.         inc    si
  1208.         jmp    short extract_text
  1209. pname5:        stosb                ;otherwise copy the character
  1210.         loop    pname4            ;copy up to 26 characters
  1211.         call    nextline        ;advance to start of next line
  1212. ;
  1213. ;Extract the menu text entries from the printer make file.
  1214. ;
  1215. extract_text:    mov    di,offset menu_table    ;initialize DI
  1216.         push    si            ;save starting address
  1217. text1:        call    skip_comment        ;skip comment lines
  1218. text2:        cmp    byte ptr [si],0        ;exit if EOF is reached
  1219.         je    extract_codes
  1220.         mov    cx,20
  1221. text3:        lodsb                ;get a character
  1222.         cmp    al,0Dh            ;finish this line and proceed
  1223.         je    text5            ;  to the next if a semicolon
  1224.         cmp    al,";"            ;  or carriage return is
  1225.         je    text4            ;  encountered
  1226.         stosb                ;copy the character
  1227.         loop    text3            ;loop back for another
  1228. text4:        call    add_spaces        ;pad text with spaces
  1229.         inc    linecount        ;register the entry
  1230.         call    nextline        ;find start of next line
  1231.         jmp    text1
  1232. text5:        call    add_spaces        ;pad text with spaces
  1233.         inc    linecount        ;register the entry
  1234.         inc    si            ;advance SI to start of
  1235.         jmp    text1            ;  next line
  1236. ;
  1237. ;Extract the control codes from the printer make file.
  1238. ;
  1239. extract_codes:    mov    code_table,di        ;save code table address
  1240.         pop    si            ;point SI to first line
  1241.         mov    cx,linecount        ;initialize line counter
  1242.         jcxz    calc_pages        ;skip if no lines
  1243. codes1:        call    skip_comment        ;skip comment lines
  1244. codes2:        lodsb                ;get a character
  1245.         cmp    al,0Dh            ;error if carriage return is
  1246.         je    code_error        ;  found before semicolon
  1247.         cmp    al,";"            ;loop back for another if this
  1248.         jne    codes2            ;  one isn't a semicolon
  1249.         push    cx            ;if a semicolon was found, call
  1250.         call    asc2bin            ;  ASC2BIN to convert the text
  1251.         pop    cx            ;  string that follows to
  1252.         jc    code_error        ;  to binary
  1253.         inc    si            ;advance SI to next line
  1254.         loop    codes1            ;loop until all lines are done
  1255. ;
  1256. ;Calculate the number of menu pages.
  1257. ;
  1258. calc_pages:    push    cs            ;restore DS
  1259.         pop    ds
  1260.         assume    ds:code
  1261.         mov    end_offset,di        ;save ending address
  1262.         mov    ax,linecount        ;exit now if there are
  1263.         or    ax,ax            ;  no entries
  1264.         jz    make_exit
  1265.         dec    ax            ;calculate number of menu
  1266.         div    ten            ;  pages
  1267.         inc    al
  1268.         mov    pagecount,al        ;store count in PAGECOUNT
  1269. make_exit:    mov    ah,49h            ;free memory allocated for
  1270.         mov    es,fileseg        ;  the file buffer
  1271.         int    21h
  1272.         ret
  1273. ;
  1274. ;Display the line number where a make error occurred, then exit.
  1275. ;
  1276. code_error:    push    cs            ;reset DS
  1277.         pop    ds
  1278.         mov    ah,9            ;display error message
  1279.         mov    dx,offset errmsg11
  1280.         int    21h
  1281.         mov    ax,linecount        ;display line number
  1282.         sub    ax,cx
  1283.         inc    ax
  1284.         call    bin2asc
  1285.         mov    ax,4C01h        ;exit with ERRORLEVEL = 1
  1286.         int    21h
  1287. make        endp
  1288.  
  1289. ;-----------------------------------------------------------------------------
  1290. ; BIN2ASC converts a binary value in AX to ASCII and displays it.
  1291. ;-----------------------------------------------------------------------------
  1292. bin2asc        proc    near
  1293.         mov    bx,10            ;initialize divisor word and
  1294.         xor    cx,cx            ;  digit counter
  1295. b2a1:        inc    cx            ;increment digit count
  1296.         xor    dx,dx            ;divide by 10
  1297.         div    bx
  1298.         push    dx            ;save remainder on stack
  1299.         or    ax,ax            ;loop until quotient is zero
  1300.         jnz    b2a1
  1301. b2a2:        pop    dx            ;retrieve a digit from stack
  1302.         add    dl,30h            ;convert it to ASCII
  1303.         mov    ah,2            ;display it
  1304.         int    21h
  1305.         loop    b2a2            ;loop until done
  1306.         ret
  1307. bin2asc        endp
  1308.  
  1309. ;-----------------------------------------------------------------------------
  1310. ; ADD_SPACES pads a menu text string with space characters.
  1311. ;-----------------------------------------------------------------------------
  1312. add_spaces    proc    near
  1313.         jcxz    add_exit
  1314.         mov    al,20h
  1315.         rep    stosb
  1316. add_exit:    ret
  1317. add_spaces    endp
  1318.  
  1319. ;-----------------------------------------------------------------------------
  1320. ; SKIP_COMMENT advances SI to the first non-comment line.
  1321. ;-----------------------------------------------------------------------------
  1322. skip_comment    proc    near
  1323.         cmp    byte ptr [si],"#"
  1324.         jne    skip_exit
  1325.         call    nextline
  1326.         jmp    skip_comment
  1327. skip_exit:    ret
  1328. skip_comment    endp
  1329.  
  1330. ;-----------------------------------------------------------------------------
  1331. ; NEXTLINE advances SI to the beginning of the next line.
  1332. ;-----------------------------------------------------------------------------
  1333. nextline    proc    near
  1334.         lodsb
  1335.         cmp    al,0Dh
  1336.         jnz    nextline
  1337.         inc    si
  1338.         ret
  1339. nextline    endp
  1340.  
  1341. ;=============================================================================
  1342. ; Buffer areas used after installation.
  1343. ;=============================================================================
  1344. pc        =    $
  1345. screen_buffer    =    pc
  1346. pc        =    pc + 1020
  1347. input_buffer    =    pc
  1348. pc        =    pc + 256
  1349. output_buffer    =    pc
  1350. pc        =    pc + 256
  1351. menu_table    =    pc
  1352.  
  1353. code        ends
  1354.         end    begin
  1355.